package models

import (
	"html/template"
	"io"
	"log"
	"sync"
	"time"
)

type TemplateBlog struct {
	*template.Template
}

type HtmlTemplate struct {
	//定义不同使用场景下所需要的template
	Index      TemplateBlog
	Category   TemplateBlog
	Custom     TemplateBlog
	Detail     TemplateBlog
	Login      TemplateBlog
	Pigeonhole TemplateBlog
	Writing    TemplateBlog
}

//将模板写入的操作进行封装
func (t *TemplateBlog) WriteData(w io.Writer, data interface{}) {
	err := t.Execute(w, data)
	if err != nil {
		//这里使用类型推断 两个err的作用域不同
		_, err := w.Write([]byte(err.Error())) // 这里也可能会出错
		if err != nil {
			log.Println(err)
			return
		}
	}
}

//如果模板出错 则在模板写入错误信息
func (t *TemplateBlog) WriteError(w io.Writer, err error) {
	if err != nil {
		_, err := w.Write([]byte(err.Error()))
		if err != nil {
			log.Println(err)
			return
		}
	}
}

//实际对Template 模板进行初始化
//这里不负责直接的构建而是负责 调用模板的加载并对公共模板进行赋值
func InitTemplate(templateDir string) (HtmlTemplate, error) { //直接就给模板的路径

	//构建一个template 返回
	tp, err := readTemplate(
		[]string{"index", "category", "custom", "detail", "login", "pigeonhole", "writing"}, //通过名字查找并加载页面
		templateDir)

	var htmlTemplate HtmlTemplate

	if err != nil {
		return htmlTemplate, err
	}
	//构建公共的Html模板并对其进行赋值

	htmlTemplate.Index = tp[0]
	htmlTemplate.Category = tp[1]
	htmlTemplate.Custom = tp[2]
	htmlTemplate.Detail = tp[3]
	htmlTemplate.Login = tp[4]
	htmlTemplate.Pigeonhole = tp[5]
	htmlTemplate.Writing = tp[6]
	return htmlTemplate, nil
}

//实际构建模板
func readTemplate(templates []string, templateDir string) (map[string]TemplateBlog, error) {

	var tbs []TemplateBlog

	w := sync.WaitGroup{}
	w.Add(len(templates))

	//对模板进行对应的加载

	for _, view := range templates {
		//这里启用多线程优化
		go func() {
			viewName := view + ".html"
			//构建一个全新的模板
			t := template.New(viewName)

			//访问博客首页模板的时候，因为有多个模板的嵌套，解析文件的时候，需要将涉及
			//到的所有模板都进行解析
			home := templateDir + "home.html"
			Header := templateDir + "layout/header.html"
			footer := templateDir + "layout/footer.html"
			personal := templateDir + "layout/personal.html"
			post := templateDir + "layout/post-list.html"
			pagination := templateDir + "layout/pagination.html"
			//这里添加了模板里面方法的映射 绑定了isODD函数
			t.Funcs(template.FuncMap{"isODD": isODD, "getNextName": getNextName,
				"date": Date, "dateDay": DateDay})
			//解析文件
			t, err := t.ParseFiles(templateDir+viewName, home, Header, footer, personal, post, pagination) //这里可以有多个文件,这里忽略了错误
			if err != nil {
				log.Panicln("解析模板出错！：", err)
				return nil, err
			}
			//因为列表时tbblog 形式 所以转换后加入
			var tb TemplateBlog //内部存储的就是模板结构 的地址 所以其是引用传递
			tb.Template = t
			tbs = append(tbs, tb)
		}()
	}
	w.Wait()
	return tbs, nil
}

//这里都是构建模板所需的方法
func isODD(num int) bool {
	//此处方法在header模板中被使用
	return num%2 == 0
}

func getNextName(str []string, index int) (res string) {
	//获得数组的元素并返回
	//此处对应header里面的方法   可以看到具体的传入值和返回值
	if index < len(str) {
		return str[index+1]
	}
	return
}

func Date(layout string) string {
	return time.Now().Format(layout)
}

func DateDay(date time.Time) string {
	//来的前端返回的数据类型
	//前端也可以返回成为date类型
	//go 的诞生时间  不同于yyyy mm 的格式方式

	return date.Format("2006-01-02 15:04:05")
}
